#include "EventManager.h"
#include "IListener.h"
#include "Event.h"

CEventManager::CEventManager() 
{
	m_bShutdown = false; 
	m_bClearFillUpdate = false;
	m_bClearFillRender = false;

}

void CEventManager::Initialize()
{
	m_bShutdown = false; 
	InitializeCriticalSection(&m_CritUpdateDeque);
	InitializeCriticalSection(&m_CritRenderDeque);
}

void CEventManager::RegisterForEventInUpdate(EVENT_TYPE sEventName,IListener* pRegisteredObject)
{
	EventReg newEvent;
	newEvent.m_pObject = pRegisteredObject;
	newEvent.m_sEvent = sEventName;

	for(unsigned int i=0;i<m_vRegisterInUpdateThread.size();++i)
		if(m_vRegisterInUpdateThread[i].m_pObject == pRegisteredObject && m_vRegisterInUpdateThread[i].m_sEvent == sEventName)
			return;

	m_vRegisterInUpdateThread.push_back(newEvent);

}

void CEventManager::RegisterForEventInRender(EVENT_TYPE sEventName,IListener* pRegisteredObject)
{
	EventReg newEvent;
	newEvent.m_pObject = pRegisteredObject;
	newEvent.m_sEvent = sEventName;

	for(unsigned int i=0;i<m_vRegisterInRenderThread.size();++i)
		if(m_vRegisterInRenderThread[i].m_pObject == pRegisteredObject && m_vRegisterInRenderThread[i].m_sEvent == sEventName)
			return;

	m_vRegisterInRenderThread.push_back(newEvent);

}

void CEventManager::UnregisterForEventInUpdate(EVENT_TYPE sEventName,IListener* pRegisteredObject)
{
	for(deque<EventReg>::iterator i=m_vRegisterInUpdateThread.begin();i!=m_vRegisterInUpdateThread.end();i++)
		if(pRegisteredObject==i->m_pObject && sEventName == i->m_sEvent)
			m_vRegisterInUpdateThread.erase(i);
}

void CEventManager::UnregisterForEventInRender(EVENT_TYPE sEventName,IListener* pRegisteredObject)
{
	for(deque<EventReg>::iterator i=m_vRegisterInRenderThread.begin();i!=m_vRegisterInRenderThread.end();i++)
		if(pRegisteredObject==i->m_pObject && sEventName == i->m_sEvent)
			m_vRegisterInRenderThread.erase(i);
}

void CEventManager::UnregisterListenerAllUpdate(IListener* pListener)
{
	for(deque<EventReg>::iterator i=m_vRegisterInUpdateThread.begin();i!=m_vRegisterInUpdateThread.end();i++)
		if(pListener==i->m_pObject )
			m_vRegisterInUpdateThread.erase(i);
}

void CEventManager::UnregisterListenerAllRender(IListener* pListener)
{
	m_vRegisterInRenderThread.clear();
}

void CEventManager::SendEventUpdateCrossToRender(EVENT_TYPE eventID, TBaseEventData *pData, unsigned int unSizeofData)
{
	if(!m_bShutdown)
	{
		for(unsigned int index = 0; index < m_vEventsFillUpdate.size(); ++index)
		{
			if(m_vEventsFillUpdate[index]->GetEventID() == eventID)
			{
				m_vEventsFillUpdate[index]->SetData( pData);
				return;
			}
		}
		CEvent* theEvent = new CEvent(eventID, pData);
		m_vEventsFillUpdate.push_back(theEvent);
	}
}

void CEventManager::SendEventRenderCrossToUpdate(EVENT_TYPE eventID, TBaseEventData *pData, unsigned int unSizeofData)
{
	if(!m_bShutdown)
	{
		for(unsigned int index = 0; index < m_vEventsFillRender.size(); ++index)
		{
			if(m_vEventsFillRender[index]->GetEventID() == eventID)
			{
				m_vEventsFillRender[index]->SetData( pData);
				return;
			}
		}
		CEvent* theEvent = new CEvent(eventID, pData);
		m_vEventsFillRender.push_back(theEvent);
	}
}

void CEventManager::SendEventUpdateLocal(EVENT_TYPE eventID, TBaseEventData *pData, unsigned int unSizeofData)
{
	if(!m_bShutdown)
	{
		for(unsigned int index = 0; index < m_vEventsLocalUpdate.size(); ++index)
		{
			if(m_vEventsLocalUpdate[index]->GetEventID() == eventID)
			{
				m_vEventsLocalUpdate[index]->SetData( pData);
				return;
			}
		}
		CEvent* theEvent = new CEvent(eventID, pData);
		m_vEventsLocalUpdate.push_back(theEvent);
	}
}

void CEventManager::SendEventRenderLocal(EVENT_TYPE eventID, TBaseEventData *pData, unsigned int unSizeofData)
{
	if(!m_bShutdown)
	{

		for(unsigned int index = 0; index < m_vEventsLocalRender.size(); ++index)
		{
			if(m_vEventsLocalRender[index]->GetEventID() == eventID)
			{
				m_vEventsLocalRender[index]->SetData( pData);
				return;
			}
		}
		CEvent* theEvent = new CEvent(eventID, pData);
		m_vEventsLocalRender.push_back(theEvent);

	}
}

void CEventManager::ProcessEventsUpdate()
{
	CEvent* End = NULL;
	CEvent* CurrEvent;

	while( m_vEventsLocalUpdate.size())
	{
		CurrEvent = m_vEventsLocalUpdate.front();
		if(CurrEvent == End)
			break;
		SendEventUpdate(CurrEvent);
		if(CurrEvent->GetReferences() == 0 && CurrEvent->GetWasHandle())
		{
			m_vEventsLocalUpdate.pop_front();
			delete CurrEvent;
			CurrEvent = NULL;
			continue;
		}
		else if(!CurrEvent->GetWasHandle())
		{
			if(End == NULL)
				End = CurrEvent;
			m_vEventsLocalUpdate.pop_front();
			m_vEventsLocalUpdate.push_back(CurrEvent);
			continue;
		}
		m_vEventsLocalUpdate.pop_front();
	}


}

void CEventManager::ProcessEventsRender()
{
	CEvent* End = NULL;
	CEvent* CurrEvent;

	while( m_vEventsLocalRender.size())
	{
		CurrEvent = m_vEventsLocalRender.front();
		if(CurrEvent == End)
			break;
		SendEventRender(CurrEvent);
		if(CurrEvent->GetReferences() == 0 && CurrEvent->GetWasHandle())
		{
			m_vEventsLocalRender.pop_front();
			delete CurrEvent;
			CurrEvent = NULL;
			continue;
		}
		else if(!CurrEvent->GetWasHandle())
		{
			if(End == NULL)
				End = CurrEvent;
			m_vEventsLocalRender.pop_front();
			m_vEventsLocalRender.push_back(CurrEvent);
			continue;
		}
		m_vEventsLocalRender.pop_front();
	}

}

void CEventManager::ClearLocalEventsUpdate()
{
	while(!m_vEventsLocalUpdate.empty())
	{
		CEvent* ToBeKill = m_vEventsLocalUpdate.front();
		m_vEventsLocalUpdate.pop_front();
		delete ToBeKill;
		ToBeKill = NULL;
	}

	m_vEventsLocalUpdate.clear();
}

void CEventManager::ClearFillEventsUpdate()
{
	
	while(!m_bClearFillUpdate){};

	while(!m_vEventsFillUpdate.empty())
	{
		CEvent* ToBeKill = m_vEventsFillUpdate.front();
		m_vEventsFillUpdate.pop_front();
		delete ToBeKill;
		ToBeKill = NULL;
	}

	m_vEventsFillUpdate.clear();
}

void CEventManager::ClearCentralEventsUpdate()
{
	while(!m_vCentralEventUpdate.empty())
	{
		CEvent* ToBeKill = m_vCentralEventUpdate.front();
		m_vCentralEventUpdate.pop_front();
		delete ToBeKill;
		ToBeKill = NULL;
	}

	m_vCentralEventUpdate.clear();
}

void CEventManager::ClearLocalEventsRender()
{
	while(!m_vEventsLocalRender.empty())
	{
		CEvent* ToBeKill = m_vEventsLocalRender.front();
		m_vEventsLocalRender.pop_front();
		delete ToBeKill;
		ToBeKill = NULL;
	}

	m_vEventsLocalRender.clear();
}

void CEventManager::ClearFillEventsRender()
{

	while(!m_bClearFillRender){};

	while(!m_vEventsFillRender.empty())
	{
		CEvent* ToBeKill = m_vEventsFillRender.front();
		m_vEventsFillRender.pop_front();
		delete ToBeKill;
		ToBeKill->SetData(NULL);
		ToBeKill = NULL;
	}

	m_vEventsFillRender.clear();
}

void CEventManager::ClearCentralEventsRender()
{
	while(!m_vCentralEventRender.empty())
	{
		CEvent* ToBeKill = m_vCentralEventRender.front();
		m_vCentralEventRender.pop_front();
		delete ToBeKill;
		ToBeKill = NULL;
	}

	m_vCentralEventRender.clear();
}

void CEventManager::ShutdownEventManager()
{
	EnterCriticalSection(&m_CritUpdateDeque);
	{
		m_bShutdown = true;
	}
	LeaveCriticalSection(&m_CritUpdateDeque);

	ShutdownEventUpdate();
	ShutdownEventRender();
}

void CEventManager::ShutdownEventUpdate()
{
	if(m_bShutdown)
	{
		m_vRegisterInUpdateThread.clear();
		ClearLocalEventsUpdate();

		EnterCriticalSection(&m_CritUpdateDeque);
		{
			ClearFillEventsUpdate();			
			ClearCentralEventsUpdate();
		}
		LeaveCriticalSection(&m_CritUpdateDeque);


		DeleteCriticalSection(&m_CritUpdateDeque);


	}
}

void CEventManager::ShutdownEventRender()
{
	if(m_bShutdown)
	{
		m_vRegisterInRenderThread.clear();
		ClearLocalEventsRender();

		EnterCriticalSection(&m_CritRenderDeque);
		{
			ClearFillEventsRender();
			ClearCentralEventsRender();
		}
		LeaveCriticalSection(&m_CritRenderDeque);


		DeleteCriticalSection(&m_CritRenderDeque);


	}
}

void CEventManager::SendEventUpdate(CEvent* pEvent)
{
	for(unsigned int i=0;i<m_vRegisterInUpdateThread.size();++i)
	{
		if(m_vRegisterInUpdateThread[i].m_sEvent == pEvent->GetEventID())
		{
			pEvent->AddRef();
			m_vRegisterInUpdateThread[i].m_pObject->ProcessEvent(pEvent);
			pEvent->SetWasHandle(true);
		}
	}
}

void CEventManager::SendEventRender(CEvent* pEvent)
{
	for(unsigned int i=0;i<m_vRegisterInRenderThread.size();++i)
	{
		if(m_vRegisterInRenderThread[i].m_sEvent == pEvent->GetEventID())
		{
			pEvent->AddRef();
			m_vRegisterInRenderThread[i].m_pObject->ProcessEvent(pEvent);
			pEvent->SetWasHandle(true);
		}
	}
}

void CEventManager::TransfertoRenderLocal()
{
	if(!m_bShutdown)
	{
		EnterCriticalSection(&m_CritRenderDeque);
		{
			while(!m_vCentralEventRender.empty())
			{
				m_vEventsLocalRender.push_back(m_vCentralEventRender.front());
				m_vCentralEventRender.pop_front();
			}
			m_vCentralEventRender.clear();
		}
		LeaveCriticalSection(&m_CritRenderDeque);
	}
}

void CEventManager::TransfertoUpdateLocal()
{
	if(!m_bShutdown)
	{
		EnterCriticalSection(&m_CritUpdateDeque);
		{

			while(!m_vCentralEventUpdate.empty())
			{
				m_vEventsLocalUpdate.push_back(m_vCentralEventUpdate.front());
				m_vCentralEventUpdate.pop_front();
			}
			m_vCentralEventUpdate.clear();

		}
		LeaveCriticalSection(&m_CritUpdateDeque);
	}
}

void CEventManager::TransfertoRenderCentral()
{

	bool bFound;
	deque<CEvent*>::iterator iter;
	if(!m_bShutdown)
	{
		EnterCriticalSection(&m_CritRenderDeque);
		{
			while(!m_vEventsFillUpdate.empty())
			{
				
				bFound = false;

				for(iter = m_vCentralEventRender.begin(); iter != m_vCentralEventRender.end(); ++iter)
				{
					if(m_vEventsFillUpdate.front()->GetEventID() == (*iter)->GetEventID())
					{
						bFound = true;
						break;
					}
				}
				
				if(!bFound)
				{
					m_vCentralEventRender.push_back(m_vEventsFillUpdate.front());
					m_vEventsFillUpdate.pop_front();
					continue;
				}
				else
				{
				
					CEvent* KILLU = (*iter);
					m_vCentralEventRender.erase(iter);
					delete KILLU;
					KILLU = NULL;
					m_vCentralEventRender.push_back(m_vEventsFillUpdate.front());
					m_vEventsFillUpdate.pop_front();
				}
			}
			m_vEventsFillUpdate.clear();
		}
		LeaveCriticalSection(&m_CritRenderDeque);
	}
}

void CEventManager::TransfertoUpdateCentral()
{

	bool bFound;
	deque<CEvent*>::iterator iter;

	if(!m_bShutdown)
	{
		EnterCriticalSection(&m_CritUpdateDeque);
		{
			while(!m_vEventsFillRender.empty())
			{
				bFound = false;

				for(iter = m_vCentralEventUpdate.begin(); iter != m_vCentralEventUpdate.end(); ++iter)
				{
					if(m_vEventsFillRender.front()->GetEventID() == (*iter)->GetEventID())
					{
						bFound = true;
						break;
					}
				}

				if(!bFound)
				{
					m_vCentralEventUpdate.push_back(m_vEventsFillRender.front());
					m_vEventsFillRender.pop_front();
					continue;
				}
				else
				{
				
					CEvent* KILLU = (*iter);
					m_vCentralEventUpdate.erase(iter);
					delete KILLU;
					KILLU = NULL;
					m_vCentralEventUpdate.push_back(m_vEventsFillRender.front());
					m_vEventsFillRender.pop_front();
				}

			}
			m_vEventsFillRender.clear();
		}
		LeaveCriticalSection(&m_CritUpdateDeque);
	}
}